package service

import (
	"backend/app/dao"
	"backend/app/model"
	"backend/utils/format"
	"backend/utils/function"
	"backend/utils/jwt"
	"backend/utils/snowflake"
	"strings"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

var UserService *userService

func init() {
	UserService = NewUserService()
}

func NewUserService() *userService {
	return &userService{}
}

type userService struct {
}

func (svr *userService) Login(p *model.UserLoginData, c *gin.Context) (data interface{}, err IServiceError) {
	username := strings.TrimSpace(p.UserName)
	if len(username) <= 0 {
		err = NewServiceError(format.CodeUserNameEmpty)
		return
	}
	password := strings.TrimSpace(p.PassWord)
	if len(password) <= 0 {
		err = NewServiceError(format.CodePasswordEmpty)
		return
	}
	user, dbErr := dao.QueryUserByUsername(username)
	if dbErr != nil {
		err = NewServiceError(format.CodeUserLoginFailed, dbErr.Error())
		return
	}
	enpassword, eErr := function.EnPwdCode([]byte(password))
	if eErr != nil {
		err = NewServiceError(format.CodePasswordWrong)
		return
	}
	if enpassword != user.PassWord {
		err = NewServiceError(format.CodePasswordWrong)
		return
	}
	zap.L().Info("-----username, password------", zap.Any("userid", user.UserID), zap.Any("name", user.UserName), zap.Any("ip", c.ClientIP()))
	if user.Status == model.UserStateForbidden {
		err = NewServiceError(format.CodeUserForbidden)
		return
	}
	token, tErr := jwt.GenToken(user.UserID, false)
	if tErr != nil {
		err = NewServiceError(format.CodeSystemError, tErr.Error())
		return
	}
	trdata := new(model.UserTokenData)
	trdata.Token = token
	trdata.UserID = user.UserID
	trdata.Forbidden = false
	switch user.Status {
	case model.UserStateForbidden:
		trdata.Forbidden = true
	}
	trdata.IsAdmin = false
	if dbErr := dao.SaveUserRedisTokenData(trdata); dbErr != nil {
		err = NewServiceError(format.CodeUserLoginFailed, dbErr.Error())
		return
	}
	data = map[string]interface{}{
		"token":   token,
		"user_id": user.UserID,
	}
	return
}

func (svr *userService) Regist(p *model.UserRegistReqData, c *gin.Context) (data interface{}, err IServiceError) {
	username := p.UserName
	password := p.Password
	rePassword := p.Repassword
	avatar := p.Avatar
	if len(username) == 0 {
		err = NewServiceError(format.CodeUserNameEmpty)
		return
	}
	// 用户密码不能为空
	if len(password) == 0 || len(rePassword) == 0 {
		err = NewServiceError(format.CodePasswordEmpty)
		return
	}
	// 用户两次输入密码不一致
	if len(password) != len(rePassword) {
		err = NewServiceError(format.CodePasswordNotSame)
		return
	}

	enpassword, eErr := function.EnPwdCode([]byte(password))
	if eErr != nil {
		zap.L().Error("userService Login EnPwdCode is error: %v", zap.Error(eErr))
		err = NewServiceError(format.CodePasswordWrong)
		return
	}
	//生成新的uid
	user := new(model.User)
	user, dbErr := dao.QueryUserByUsername(username)
	if dbErr != nil {
		if dbErr.Error() != "用户不存在" {
			zap.L().Error("userService Register QueryUserByUsername is error", zap.Error(dbErr))
			err = NewServiceError(format.CodeDatabaseErr)
			return
		}
		user.UserID = snowflake.GenID()
		user.UserName = username
		user.Status = 0
	}
	user.PassWord = enpassword
	if dbErr := dao.SaveUser(user); dbErr != nil {
		zap.L().Error("userService Register SaveUser is error: %v", zap.Error(dbErr))
		err = NewServiceError(format.CodeDatabaseErr)
		return
	}

	// 初始化用户信息
	userinfo := new(model.UserInfo)
	userinfo.UserID = user.UserID
	userinfo.RoleName = "玩家"
	if len(avatar) == 0 {
		userinfo.Avatar = "https://img1.baidu.com/it/u=1653751609,236581088&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=500"
	} else {
		userinfo.Avatar = avatar
	}
	userinfo.Power = 0
	if dbErr := dao.SaveUserInfo(userinfo); dbErr != nil {
		err = NewServiceError(format.CodeDatabaseErr, dbErr.Error())
		return
	}

	// 初始化角色
	newUserRole := new(model.UserRole)
	newUserRole.RoleId = int32(1)
	newUserRole.UserId = user.UserID
	if dbErr := dao.SaveUserRole(newUserRole); dbErr != nil {
		zap.L().Error("SaveUserRole is dbErr", zap.Error(dbErr))
		err = NewServiceError(format.CodeDatabaseErr, dbErr.Error())
		return
	}

	data = map[string]interface{}{
		"username": user.UserName,
	}
	return
}

func (svr *userService) GetUserTokenData(userID int64) (*model.UserTokenData, error) {
	return dao.QueryUserRedisTokenData(userID)
}

func (svr *userService) GetUserByID(userID int64) (*model.User, error) {
	return dao.QueryUserByID(userID)
}

func (svr *userService) GetUserInfo(userID int64) (data interface{}, err IServiceError) {
	userInfo, dbErr := dao.QueryUserInfo(userID)
	if dbErr != nil {
		zap.L().Error("GetUserInfo QueryUserInfo is error", zap.Error(dbErr))
		err = NewServiceError(format.CodeUserNotExist, dbErr.Error())
		return
	}
	user, dbErr := dao.QueryUserByID(userID)
	if dbErr != nil {
		zap.L().Error("GetUserInfo QueryUserByID is error", zap.Error(dbErr))
		err = NewServiceError(format.CodeUserNotExist, dbErr.Error())
		return
	}
	userRoles, dbErr := dao.QueryUserRoles(userID)
	if dbErr != nil {
		zap.L().Error("GetUserInfo QueryUserRoles is error", zap.Error(dbErr))
		err = NewServiceError(format.CodeUserNotExist, dbErr.Error())
		return
	}
	userInfoShow := new(model.UserInfoShow)
	userInfoShow.UserID = userInfo.UserID
	userInfoShow.RoleName = userInfo.RoleName
	userInfoShow.Avatar = userInfo.Avatar
	userInfoShow.Power = userInfo.Power
	userInfoShow.IsBid = false
	userInfoShow.Roles = make([]string, 0)
	if user.Status == 1 {
		userInfoShow.IsBid = true
	}
	for _, userRole := range userRoles {
		role, dbErr := dao.QueryRoleByID(userRole.RoleId)
		if dbErr != nil {
			continue
		}
		userInfoShow.Roles = append(userInfoShow.Roles, role.RoleName)
	}
	data = userInfoShow
	return
}
